﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;

namespace ChatApplicationServer
{
    class Server
    {
        public TcpListener server;
        public static List<TcpClient> clients = new List<TcpClient>();
        public static List<string> Names = new List<string>();
        public static int NumberOfClients = 0;
        private const int port = 2000;
        private Thread counter;
        public Server()
        {
            server = new TcpListener(IPAddress.Any, port);
        }
        public void StartListening()
        {
            server.Start();
            while(NumberOfClients < 4)
            {
                if(server.Pending())
                {
                    TcpClient connection = server.AcceptTcpClient();
                    Console.WriteLine(connection.Client.RemoteEndPoint + " Connected");
                    Communicator comm = new Communicator(connection);
                    NumberOfClients++;
                }
                Thread.Sleep(1000);
            }
            counter = new Thread(CheckForOpenings);
            counter.Start();
        }
        private void CheckForOpenings()
        {
            while(true)
            {
                if(NumberOfClients < 4)
                {
                    break;
                }
            }
            StartListening();
        }
        public static void SendToAll(string name, string msg, TcpClient client)
        {
            StreamWriter writer;
            for(int i = 0; i < Server.clients.Count - 1;i++)
            {
                try
                {
                    if (clients[i] != client)
                    {
                        writer = new StreamWriter(clients[i].GetStream());
                        writer.WriteLine(name + ": " + msg);
                        writer.Flush();
                    }
                }
                catch(Exception)
                {
                    Server.SendSessionMessage(Names[i] + " has left the room");
                    Server.clients.Remove(clients[i]);
                    Server.Names.Remove(Names[i]);
                    Server.NumberOfClients--;
                }
            }
        }
        public static void SendSessionMessage(string msg)
        {
            StreamWriter writer;
            for (int i = 0; i < Server.clients.Count - 1; i++)
            {
                try
                {
                    writer = new StreamWriter(clients[i].GetStream());
                    writer.WriteLine(msg);
                    writer.Flush();
                }
                catch (Exception)
                {
                    Server.clients.Remove(clients[i]);
                    Server.Names.Remove(Names[i]);
                    NumberOfClients--;
                }
            }
        }
    }
    class Communicator
    {
        private TcpClient client;
        private StreamReader reader;
        private StreamWriter writer;
        public string Name { get; private set; }
        public Communicator(TcpClient connection)
        {
            client = connection;
            Thread thread = new Thread(WelcomeUser);
            thread.Start();
        }
        private void run()
        {
            String msg = "";
            try
            {
                while(true)
                {
                    msg = reader.ReadLine();
                    Server.SendToAll(Name, msg, client);
                    Thread.Sleep(500);
                }
            }
            catch (Exception)
            {
                Console.WriteLine(client.Client.RemoteEndPoint + " Disconnected");
            }
        }
        private string AskForName()
        {
            try
            {
                writer.WriteLine("Who are you?");
                writer.Flush();
                return reader.ReadLine();
            }
            catch (Exception)
            {
                throw;
            }
            return "";
        }
        private void WelcomeUser()
        {
            reader = new StreamReader(client.GetStream());
            writer = new StreamWriter(client.GetStream());
            Name = AskForName();
                try
                {
                    while(Server.Names.Contains(Name))
                    {
                            writer.WriteLine("Name exists");
                            writer.Flush();
                            Name = AskForName();
                    }
                        Server.clients.Add(client);
                        Server.Names.Add(Name);
                        Server.SendSessionMessage("--" + Name + " HAS ENTERED THE ROOM.");
                        Thread thread = new Thread(run);
                        thread.Start();
                }
                catch (Exception)
                {

                }
        }
    }
}
